<?php

namespace app\admin\controller;

use app\common\controller\Backend;
use HtmlToWord\Parse;
use PhpOffice\Math\Math;
use PhpOffice\PhpWord\IOFactory;
use PhpOffice\PhpWord\PhpWord;
use think\Request;
use function fast\e;

/**
 * 线性数学计算器
 * @internal
 */
class Calculator extends Backend
{

    protected $noNeedLogin = ['index', 'detail', 'add', 'exportKatex', 'exportWord', 'exportLatex'];
    protected $model = null;

    public function _initialize()
    {
        parent::_initialize();
        $this->model = new \app\admin\model\Calculator();
        //移除HTML标签
        $this->request->filter('trim,strip_tags,htmlspecialchars');
    }

    public function index()
    {
        return returnJson($this->model->all());
    }

    /**
     * 获取详情
     * @return void
     */
    public function detail()
    {
        $id = $this->request->post("id");
        if (!$id) {
            return returnJson([], '参数错误');
        }
        return returnJson($this->model->get($id));
    }

    /**
     * 新增
     * @return void
     */
    public function add()
    {
        $title = $this->request->post("title");
        $content = $this->request->post("content");
        if (!$title)
            return returnJson([], '请输入标题', 403);

        if (!$content)
            return returnJson([], '请输入数据内容', 402);
        if (strpos($content, '[') === false || strpos($content, ']') === false || strpos($content, ',') === false || strpos($content, ';') === false)
            return returnJson([], '数据格式错误', 405);

        $str = trim(trim($content, '['), ']');
        $str = explode(';', $str);
        $first = 0;
        if (!$str) {
            return returnJson([], '数据错误', 404);
        }
        foreach ($str as $key => $item) {
            $column = explode(',', $item);
            $num = count($column);
            if ($key==0)
                $first = $num;
            if ($num != $first)
                return returnJson([], '数据错误，请检查后录入', 401);
        }
        $insert = [
            'title' => $title,
            'content' => $content,
        ];
        if ($this->model->create($insert)) {
            return returnJson('新增成功');
        }
        return returnJson([], '新增失败，请稍后重试', 400);
    }

    /**
     * 导出数学公式
     * @return void
     */
    public function exportWord()
    {
        $domain = $_SERVER['HTTP_HOST'];
        $data = $this->request->post(false);
        if (!isset($data['data']) || !$data['data']) {
            return returnJson([], '数据不能为空', 406);
        }
        if (!isset($data['img']) || !$data['img']) {
            return returnJson([], '参数错误', 406);
        }
        $img = $data['img'];
        $data = json_decode($data['data'], true);
        $mathMl = "<math xmlns='http://www.w3.org/1998/Math/MathML' display='block'><mtable>";
        $mathFoot = '</mtable></math>';
        foreach ($data as $k => $v) {
            //如果是第一行，需要添加基础数据在最上面
            if ($k == 0) {
                $mathMl .= '<mtr><mtd><mrow>';
                $mathMl .= $this->makeMathMl($v['initData']);
                $mathMl .= '</mrow></mtd></mtr>';
                $mathMl .= '<mtr></mtr><mtr></mtr>';
                $mathMl .= '<mtr><mtd><mrow>';
                $mathMl .= $this->makeFormula($v);
                $mathMl .= $this->makeMathMl($v['resultTableData']);
                $mathMl .= '</mrow></mtd></mtr>';
            } else {
                //不是第一行 左侧添加表达式
                $mathMl .= '<mtr></mtr><mtr></mtr>';
                $mathMl .= '<mtr><mtd><mrow>';
                $mathMl .= $this->makeFormula($v);
                $mathMl .= $this->makeMathMl($v['resultTableData']);
                $mathMl .= '</mrow></mtd></mtr>';
            }
        }
        $mathMl .= $mathFoot;
        $imgArr = explode(',', $img);
        $res = json_decode($this->request_post('http://exportword.ah.tswm.club/export_word', ['data'=>$mathMl, 'img'=>$imgArr[1]]), true);
        if ($res['code'] == 200) {
            return returnJson(['download'=>'https://'.$domain.'/python/'.$res['path']], '导出成功');
        }
        return returnJson([], '导出失败', 406);

//        $command = 'python3 '.$_SERVER["DOCUMENT_ROOT"].'/py/app.py "'.$mathMl.'"';
//        $returnArr = 0;
//        $res = [];
//        $res = exec($command. " 2>&1", $res, $returnArr);
//        echo $command. " 2>&1";
//        var_dump($res, $returnArr);

//        $output = [];
//        $returnData = 0;
//        exec("python ".$_SERVER['DOCUMENT_ROOT']."/py/latextoword.py {$params} 2>&1", $output, $returnData);
//        var_dump("python ".$_SERVER['DOCUMENT_ROOT']."/py/latextoword.py ".escapeshellarg($mathMl));
//        var_dump($output);
//        var_dump($returnData);
//        echo $mathMl;
        // Creating the new document...
//        $phpWord = new PhpWord();

        /* Note: any element you append to a document must reside inside of a Section. */

// Adding an empty Section to the document...
//        $section = $phpWord->addSection();
//
//        $omml = Parse::math2omml($mathMl);
//        $section->addText($omml);


// Saving the document as OOXML file...
//        $objWriter = IOFactory::createWriter($phpWord, 'Word2007');
//        $objWriter->save('helloWorld.docx');
//        $downPath = '/docs/'.date('Ymd').time().'.docx';
//        $savePath = $_SERVER['DOCUMENT_ROOT'].$downPath;
//        $objWriter->save($savePath);
//        echo $downPath;
//        $parse = new Parse();
//        $parse::math2omml($mathMl);
//        echo $parse->getBody();
//        return 1;
//        $mathMl = '<math xmlns="http://www.w3.org/1998/Math/MathML" display="inline"><mrow><mi>$</mi><mrow><mi>&</mi><mrow><mo stretchy="true" fence="true" form="prefix">&#x00028;</mo><mtable><mtr><mtd columnalign="center"><mn>2</mn></mtd><mtd columnalign="center"><mn>5</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>1</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>7</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>3</mn></mtd></mtr><mtr><mtd columnalign="center"><mn>1</mn></mtd><mtd columnalign="center"><mn>3</mn></mtd><mtd columnalign="center"><mn>0</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>5</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>3</mn></mtd></mtr><mtr><mtd columnalign="center"><mn>1</mn></mtd><mtd columnalign="center"><mn>3</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>1</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>4</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>4</mn></mtd></mtr><mtr><mtd columnalign="center"><mn>2</mn></mtd><mtd columnalign="center"><mn>6</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>1</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>9</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>7</mn></mtd></mtr></mtable><mo stretchy="true" fence="true" form="postfix">&#x00029;</mo></mrow><mspace width="0.278em" /><mover><mrow><mrow><msub><mrow><mi>r</mi></mrow><mrow><mn>1</mn></mrow></msub></mrow><mo>&#x02194;</mo><mrow><msub><mrow><mi>r</mi></mrow><mrow><mn>3</mn></mrow></msub></mrow></mrow><mo>&#x0007E;</mo></mover><mspace width="0.278em" /><mrow><mo stretchy="true" fence="true" form="prefix">&#x00028;</mo><mtable><mtr><mtd columnalign="center"><mn>1</mn></mtd><mtd columnalign="center"><mn>3</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>1</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>4</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>4</mn></mtd></mtr><mtr><mtd columnalign="center"><mn>1</mn></mtd><mtd columnalign="center"><mn>3</mn></mtd><mtd columnalign="center"><mn>0</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>5</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>3</mn></mtd></mtr><mtr><mtd columnalign="center"><mn>2</mn></mtd><mtd columnalign="center"><mn>5</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>1</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>7</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>3</mn></mtd></mtr><mtr><mtd columnalign="center"><mn>2</mn></mtd><mtd columnalign="center"><mn>6</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>1</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>9</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>7</mn></mtd></mtr></mtable><mo stretchy="true" fence="true" form="postfix">&#x00029;</mo></mrow><mspace width="0.278em" /><mover><mrow><mo stretchy="false">&#x00028;</mo><mn>5</mn><mo stretchy="false">&#x00029;</mo><mi>&#x000D7;</mi><mrow><msub><mrow><mi>r</mi></mrow><mrow><mn>4</mn></mrow></msub></mrow></mrow><mo>&#x0007E;</mo></mover><mspace width="0.278em" /><mrow><mo stretchy="true" fence="true" form="prefix">&#x00028;</mo><mtable><mtr><mtd columnalign="center"><mn>1</mn></mtd><mtd columnalign="center"><mn>3</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>1</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>4</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>4</mn></mtd></mtr><mtr><mtd columnalign="center"><mn>1</mn></mtd><mtd columnalign="center"><mn>3</mn></mtd><mtd columnalign="center"><mn>0</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>5</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>3</mn></mtd></mtr><mtr><mtd columnalign="center"><mn>2</mn></mtd><mtd columnalign="center"><mn>5</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>1</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>7</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>3</mn></mtd></mtr><mtr><mtd columnalign="center"><mn>10</mn></mtd><mtd columnalign="center"><mn>30</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>5</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>45</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>35</mn></mtd></mtr></mtable><mo stretchy="true" fence="true" form="postfix">&#x00029;</mo></mrow><mspace width="0.278em" /><mover><mrow><mrow><msub><mrow><mi>r</mi></mrow><mrow><mn>4</mn></mrow></msub></mrow><mo>&#x0002B;</mo><mo stretchy="false">&#x00028;</mo><mo>&#x02212;</mo><mn>10</mn><mo stretchy="false">&#x00029;</mo><mi>&#x000D7;</mi><mrow><msub><mrow><mi>r</mi></mrow><mrow><mn>1</mn></mrow></msub></mrow></mrow><mo>&#x0007E;</mo></mover><mspace width="0.278em" /><mrow><mo stretchy="true" fence="true" form="prefix">&#x00028;</mo><mtable><mtr><mtd columnalign="center"><mn>1</mn></mtd><mtd columnalign="center"><mn>3</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>1</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>4</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>4</mn></mtd></mtr><mtr><mtd columnalign="center"><mn>1</mn></mtd><mtd columnalign="center"><mn>3</mn></mtd><mtd columnalign="center"><mn>0</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>5</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>3</mn></mtd></mtr><mtr><mtd columnalign="center"><mn>2</mn></mtd><mtd columnalign="center"><mn>5</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>1</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>7</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>3</mn></mtd></mtr><mtr><mtd columnalign="center"><mn>0</mn></mtd><mtd columnalign="center"><mn>0</mn></mtd><mtd columnalign="center"><mn>5</mn></mtd><mtd columnalign="center"><mo>&#x02212;</mo><mn>5</mn></mtd><mtd columnalign="center"><mn>5</mn></mtd></mtr></mtable><mo stretchy="true" fence="true" form="postfix">&#x00029;</mo></mrow></mrow><mi>$</mi></mrow></math>';
//var_dump($mathMl);return;
//        $word = new PhpWord();
        // 创建新页面
//        $section = $word->addSection();
        // 添加数学公式
        // 添加带有 MathML 的文本运行
//        $math = new Math();
//        $math->setMathMl($mathMl);
//        $textRun->addText($mathMl);
        // 保存文档
//        $objWriter = IOFactory ::createWriter($word, 'Word2007');
//        $downPath = '/docs/'.date('Ymd').time().'.docx';
//        $savePath = $_SERVER['DOCUMENT_ROOT'].$downPath;
//        $objWriter->save($savePath);
//        echo $downPath;
    }

    /**
     * 生成公式
     */
    public function makeFormula($data)
    {
        $mathMl = '';
        switch($data['type']) {
            case 1:
                $mathMl .= '<mtable>';
                $mathMl .= '<mtr><mtd></mtd><mtd><mrow><mo>~</mo></mrow></mtd></mtr>';
                $mathMl .= '<mtr><mtd>';
                $mathMl .= '<msub><mi>r</mi><mn>'.($data['changeValue1']+1).'</mn></msub></mtd><mtd><mo>↔</mo></mtd><mtd><msub><mi>r</mi><mn>'.($data['changeValue2']+1).'</mn></msub></mtd>';
                $mathMl .= '<mtd></mtd><mtd></mtd></mtr></mtable>';
                break;
            case 2:
                $mathMl .= '<mtable>';
                $mathMl .= '<mtr><mtd><mrow><mo>~</mo></mrow></mtd></mtr>';
                $mathMl .= '<mtr>';
                $mathMl .= '<mtd><mrow><mo>(</mo><mn>'.($data['xValue']).'</mn><mo>)</mo><mo>×</mo></mrow></mtd><mtd><msub><mi>r</mi><mn>'.($data['mulLineNum']).'</mn></msub></mtd><mtd>';
                $mathMl .= '</mtd><mtd></mtd><mtd></mtd></mtr></mtable>';
                break;
            case 3:
                $mathMl .= '<mtable>';
                $mathMl .= '<mtr><mtd></mtd><mtd></mtd><mtd><mrow><mo>~</mo></mrow></mtd></mtr>';
                $mathMl .= '<mtr><mtd>';
                $mathMl .= '<msub><mi>r</mi><mn>'.($data['addLineNum']).'</mn></msub></mtd><mtd><mo>+</mo></mtd><mtd><mo>(</mo><mn>'.($data['xValue']).'</mn><mo>)</mo></mtd><mtd><mo>×</mo><msub><mi>r</mi><mn>'.($data['mulLineNum']).'</mn></msub></mtd>';
                $mathMl .= '<mtd></mtd><mtd></mtd></mtr></mtable>';
                break;
        }
        return $mathMl;
    }

    /**
     * 生成方程式mathMl
     * @param $data
     * @return string
     */
    public function makeMathMl($data)
    {
//        $mathMl = '<mo>(</mo><mtable>';
        $mathMl = "<mfenced open='(' close=')'><mtable>";
        foreach($data as $initItem) {
            $mathMl .= '<mtr>';
            foreach ($initItem as $rowItem) {
//                var_dump($rowItem);
                $mathMl .= '<mtd><mn>'.$rowItem.'</mn></mtd>';
            }
            $mathMl .= '</mtr>';
        }
        return $mathMl.'</mtable></mfenced>';
    }


    function request_post($url = '', $curlPost = '') {
        if (empty($url) || empty($curlPost)) {
            return false;
        }
        $postUrl = $url;
        $ch = curl_init();//初始化curl
        curl_setopt($ch, CURLOPT_URL,$postUrl);//指定网页
        curl_setopt($ch, CURLOPT_HEADER, 0);//设置header
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//    将curl_exec()获取的信息以文件流的形式返回，而不是直接输出
        curl_setopt($ch, CURLOPT_POST, 1);//post提交方式
        curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost); //全部数据使用HTTP协议中的"POST"操作来发送。要发送文件，在文件名前面加上@前缀并使用完整路径。这个参数可以通过urlencoded后的字符串类似'para1=val1&para2=val2&...'或使用一个以字段名为键值，字段数据为值的数组。如果value是一个数组，Content-Type头将会被设置成multipart/form-data
        $data = curl_exec($ch);//运行curl
        curl_close($ch); // 关闭一个cURL会话
        return $data;
    }

    /**
     * 导出latex
     * @return void
     */
    public function exportLatex()
    {
        $domain = $_SERVER['HTTP_HOST'];
        $data = $this->request->post(false);
        if (!isset($data['data']) || !$data['data']) {
            return returnJson([], '数据不能为空', 406);
        }
        $data = json_decode($data['data'], true);
        $katexStr = '$\begin{aligned}&';
        foreach ($data as $k => $v) {
            //如果是第一行，需要添加基础数据在最上面
            if ($k == 0) {
                $katexStr .= $this->makeLatexEquation($v['initData']);
                $katexStr .= $this->makeLatexFormula($v);
                $katexStr .= $this->makeLatexEquation($v['resultTableData']);
            } else {
                $katexStr .= $this->makeLatexFormula($v);
                $katexStr .= $this->makeLatexEquation($v['resultTableData']);
            }
        }
        $katexStr = rtrim($katexStr, '\\  &  \\  &\;').'\\end{aligned}$';
        // 实例化
        $phpWord = new PhpWord();
        header("Content-Type: text/html; charset=UTF-8");
        // 创建新页面
        $section = $phpWord->addSection();
        $section->addText($katexStr);
        // 保存 Word 文档到指定路径
        $objWriter = IOFactory ::createWriter($phpWord, 'Word2007');
        $downPath = '/docs/Latex'.date('Ymd').time().'.docx';
        $savePath = $_SERVER['DOCUMENT_ROOT'].$downPath;
        $objWriter->save($savePath);
        return returnJson(['download'=>'https://'.$domain.$downPath], '导出成功');
    }

    /**
     * 生成latex方程式
     */
    public function makeLatexEquation($data)
    {
        $latexStr = '\left(\begin{array}{';
        $lineMaxKey = count($data)-1;
        foreach ($data as $k => $v) {
            $count = count($v);
            $line = '';
            $c = '';
            foreach ($v as $item) {
                $line .= $item.' & ';
                $c .= 'c';
            }
            if ($k==0) {
                $latexStr .= $c.'} ';
            }
            $latexStr .= rtrim($line, ' & ');
            if ($k == $lineMaxKey) {
                $latexStr .= '\end{array}\right)\\\\  &  \\\\  &\\;';
            } else {
                $latexStr .= '\\\\';
            }
        }
        return $latexStr;
    }

    /**
     * 生成latex公式
     */
    public function makeLatexFormula($data)
    {
        $latex = '';
        switch($data['type']) {
            case 1:
                $latex .= '\\widetilde{{{r}_{'.($data['changeValue1']+1).'}}\\leftrightarrow {{r}_{'.($data['changeValue2']+1).'}}}\\;';
                break;
            case 2:
                $val = $data['xValue'];
                if (strpos($val, '/')) {
                    $valArr = explode('/', $val);
                    $val = 'frac{'.$valArr[0].'}{'.$valArr[1].'}';
                }
                $latex .= '\\widetilde{('.$val.')\\times{{r}_{'.$data['mulLineNum'].'}}}\\;';
                break;
            case 3:
                $val = $data['xValue'];
                if (strpos($val, '/')) {
                    $valArr = explode('/', $val);
                    $val = 'frac{'.$valArr[0].'}{'.$valArr[1].'}';
                }
                $latex .= '\\widetilde{{{r}_{'.$data['addLineNum'].'}}+('.$val.') \\times {{r}_{'.$data['mulLineNum'].'}}}\\;';
                break;
        }
        return $latex;
    }
}
